import { Initializer } from "@/utils/graph/Initializer";
import { Node } from "@/utils/graph/Node";
import { Link } from "@/utils/graph/Link";
import { Type } from "@/utils/graph/Type";

/**
 * 知识图谱对象
 * @param gid 容纳svg元素div的id
 * @param isFullscreen 是否全屏，false：长宽为gid指定div长宽
 * @param kgInfo 知识图谱初始信息
 *    必须：节点数组nodes与连接数组links;
 *    可选：图谱名称、id;
 * @param vueComponent 当前KG对象所在的vue组件
 * @param nameMapInfo 知识图谱映射信息，用于转换为本对象可以理解的名称
 *    必须：nodes与links各属性传入时在kgInfo中的名称字符串
 * @constructor
 */
export function KG(gid, isFullscreen, kgInfo, vueComponent, nameMapInfo) {
  this.kgInfo = kgInfo;

  this.vueComponent = vueComponent; //当前KG对象所在的vue组件

  this.update = {
    nodes:0,
    links:0,
    typeList:0,
    historyList:0
  };

  this.gid = gid; //绘图画布div节点id
  this.gcontainer = {}; // gid对应div对象
  this.svg = {};  // 绘图svg对象

  this.initializer = new Initializer(this); //初始化工作对象

  //当前鼠标所在的Node
  this.viewNode = {
    valid:false //当前信息是否有效
  };
  this.selectedNode = {}; //当前选择的Node
  this.selectedNodeUpdate = 0; //选择节点更新监视器

  this.arrowMarker = {};
  this.qaGraphNode = {};
  this.qaButtonGroup = {};
  this.qaGraphNodeText = {};
  this.qaGraphLink = {};
  this.qaGraphLinkText = {};

  this.graphNode = {};
  this.graphNodeText = {};
  this.graphNodeButtonGroup = {};
  this.graphLink = {};
  this.graphLinkText = {};

  this.simulation = {}; //力模型对象
  this.zoom = {}; //缩放对象
  this.dataFormatter = {}; //内部数据计算对象
  this.drawer = {}; //元素绘制对象
  this.eventManager = {}; //事件管理对象
  this.elementEditor = {}; //图谱编辑操作对象
  this.buttonGroupManager = {}; //按钮组相关操作对象
  this.typeManager = {}; //类型管理对象
  this.historyManager = {}; //历史管理对象

  if(nameMapInfo==null) {
    nameMapInfo = defaultNameMapInfo
  }
  this.initializer.initKG(nameMapInfo,isFullscreen);

  /**---------------------------------------------------------------------------
   * 开始渲染
   */
  this.display = function(){

    this.initializer.display();

  }

  /**---------------------------------------------------------------------------
   * 添加节点外界接口
   * @param uuid
   * @param uri
   * @param label
   * @param typeId
   */
  this.addNode = function(uuid,uri,label,typeId){
    let type = this.typeManager.getTypeById(typeId);
    let node = new Node(uuid,uri,label,type);
    this.elementEditor.addNode(node);
  }

  /**---------------------------------------------------------------------------
   * 添加连接外界接口
   * @param uuid
   * @param predicate
   * @param sId
   * @param tId
   */
  this.addLink = function(uuid,predicate,sId,tId) {
    let link = new Link(uuid,predicate,sId,tId);
    this.elementEditor.addLink(link);
  }

  /**---------------------------------------------------------------------------
   * 编辑节点外界接口
   * @param uuid
   * @param uri
   * @param label
   * @param typeId
   * @param color
   * @param r
   */
  this.editNode = function(uuid,uri,label,typeId,color,r){
    let type = this.typeManager.getTypeById(typeId);
    let node = new Node(uuid,uri,label,type,color,r);
    this.elementEditor.editNode(node);
  }

  /**---------------------------------------------------------------------------
   * 编辑连接外界接口
   * @param uuid
   * @param predicate
   * @param sId
   * @param tId
   */
  this.editLink = function(uuid,predicate,sId,tId){
    let link = new Link(uuid,predicate,sId,tId);
    this.elementEditor.editLink(link);
  }

  /**---------------------------------------------------------------------------
   * 根据id删除节点
   * @param id
   */
  this.deleteNodeById = function(id) {
    this.elementEditor.deleteNodeById(id);
  }

  /**---------------------------------------------------------------------------
   * 根据id删除连接
   * @param id
   */
  this.deleteLinkById = function(id) {
    this.elementEditor.deleteLinkById(id);
  }

  /**---------------------------------------------------------------------------
   * 根据id获取某一结点副本
   * @param id
   * @returns {any}
   */
  this.getNodeById = function(id){
    let node = this.elementEditor.getNodeById(id);
    if(node==null) return null;
    return JSON.parse(JSON.stringify(node));
  }

  /**---------------------------------------------------------------------------
   * 根据类型名获取节点
   * @param name
   */
  this.getNodesByTypeName = function(name) {
    return this.elementEditor.getNodesByTypeName(name);
  }

  /**---------------------------------------------------------------------------
   * 根据id获取连接副本
   * @param id
   * @returns {null|any}
   */
  this.getLinkById = function(id){
    let link = this.elementEditor.getLinkById(id);
    if(link==null) return null;
    return JSON.parse(JSON.stringify(link));
  }

  /**---------------------------------------------------------------------------
   * 回到开始位置
   */
  this.zoomToStart = function() {
    this.zoom.zoomToStart();
  }

  /**---------------------------------------------------------------------------
   * 定位节点外界接口
   * @param id
   */
  this.zoomToNode = function(id){
    let node = this.elementEditor.getNodeById(id);
    this.zoom.zoomToNode(node);
  }

  /**---------------------------------------------------------------------------
   * 定位连接外界接口
   * @param id
   */
  this.zoomToLink = function(id){
    let link = this.elementEditor.getLinkById(id);
    let sNode = this.elementEditor.getNodeById(link.sId);
    let tNode = this.elementEditor.getNodeById(link.tId);
    this.zoom.zoomToLink(sNode,tNode);
  };

  /**
   * 定位到特定位置
   * @param x
   * @param y
   * @param scale
   */
  this.zoomToPosition = function(x, y, scale) {
    this.zoom.zoomToPosition(x, y, scale);
  };

  /**---------------------------------------------------------------------------
   * 选择节点
   * @param id
   */
  this.focusNode = function(id) {
    let node = this.elementEditor.getNodeById(id);
    this.elementEditor.focusNode(node);
  }

  /**---------------------------------------------------------------------------
   * 固定所有节点
   */
  this.fixAll = function(){
    this.elementEditor.fixAll();
  }

  /**---------------------------------------------------------------------------
   * 释放所有节点
   */
  this.freeAll = function(){
    this.elementEditor.freeAll();
  }

  /**---------------------------------------------------------------------------
   * 添加类型外界接口
   * @param id
   * @param name
   */
  this.addType = function(id,name){
    let type = new Type(id,name);
    this.typeManager.addType(type);
  }

  /**---------------------------------------------------------------------------
   * 根据名称获取类型对象副本
   * @param name
   * @returns {null|any}
   */
  this.getTypeByName = function(name) {
    let type = this.typeManager.getTypeByName(name);
    if(type == null) return null;
    return JSON.parse(JSON.stringify(type));
  }

  /**---------------------------------------------------------------------------
   * 根据索引获取类型对象副本
   * @param index
   * @returns {null|any}
   */
  this.getTypeByIndex = function(index) {
    let type = this.typeManager.getTypeByIndex(index);
    if(type == null) return null;
    return JSON.parse(JSON.stringify(type));
  }

  /**---------------------------------------------------------------------------
   * 根据id获取类型
   * @param id
   */
  this.getTypeById = function(id) {
    let type = this.typeManager.getTypeById(id);
    if(type == null) return null;
    return JSON.parse(JSON.stringify(type));
  }

  /**---------------------------------------------------------------------------
   * 修改类型
   * @param oldType
   * @param newType
   */
  this.modifyType = function(oldType, newType) {
    this.typeManager.modifyType(oldType,newType);
  }

  /**---------------------------------------------------------------------------
   * 根据id删除类型
   * @param typeId
   */
  this.deleteTypeById = function(typeId) {
    this.typeManager.deleteTypeById(typeId);
  }

  /**---------------------------------------------------------------------------
   * 展示某种类型的节点
   * @param selectTypeIdArr
   */
  this.modifyTypeShow = function(selectTypeIdArr) {
    this.elementEditor.switchTypeShow(selectTypeIdArr);
  }

  /**---------------------------------------------------------------------------
   * 撤回到某一步历史
   * @param id
   */
  this.withdrawHistory = function(id=null) {
    if(id==null) this.historyManager.withdraw();
    else this.historyManager.withdrawTo(id);
  }

  /**---------------------------------------------------------------------------
   * 改变某个事件的有效性
   */
  this.changeEvents = function(changes){
    this.eventManager.changeEvents(changes);
  }

}

let defaultNameMapInfo = {
  kgNameName: "kgName",
  kgIdName: "kgID",
  typeListName: "types",
  nodesName: "nodes",
  linksName: "properties",
  typeIdName: "id",
  nodeIdName: "id",
  linkIdName: "id",
  typeNameName: "label_ZH",
  typeColorName: "color",
  typeRName: "radius",
  nodeUriName: "uri",
  nodeLabelName: "label_ZH",
  nodeTypeIdName: "typeId",
  sIdName: "sourceId",
  tIdName: "targetId",
  predicateName: "label_ZH",
  nodeColorName: "color",
  nodeRName: "radius",
  nodeXName: "hor",
  nodeYName: "ver"
};
